package com.liuyun.symmetric.des;

import com.liuyun.util.Base64Util;
import lombok.SneakyThrows;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;

/**
 * 3重DES算法
 * <p>
 * Copyright: (C), 2021/1/25 22:02
 * <p>
 * <p>
 * Company Information & Data Security Solutions Co., Ltd.
 *
 * @author LiuYun liujw@idss-cn.com
 * @version 1.0
 */
public class DesEdeUtil {
    static {
//        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 密钥的算法
     */
    public static final String KEY_ALGORITHM = "DESede";

    /**
     * 加解密算法
     */
    public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";

    /**
     * 生成密钥
     *
     * @return
     */
    @SneakyThrows
    public static byte[] initKey() {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGenerator.init(168);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成密钥
     *
     * @return
     */
    @SneakyThrows
    public static byte[] initKey(int length) {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGenerator.init(length);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 根据密钥字节，恢复密钥对象
     *
     * @param key
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    @SneakyThrows
    private static SecretKey toKey(byte[] key) {
        DESedeKeySpec desKeySpec = new DESedeKeySpec(key);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
        return secretKey;
    }

    /**
     * 加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 密文
     */
    @SneakyThrows
    public static byte[] encrypt(byte[] data, byte[] key) {
        SecretKey secretKey = toKey(key);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return
     */
    @SneakyThrows
    public static byte[] decrypt(byte[] data, byte[] key) {
        SecretKey secretKey = toKey(key);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 加密
     *
     * @param data      待加密数据
     * @param base64Key 密钥
     * @return 密文
     */
    @SneakyThrows
    public static byte[] encrypt(byte[] data, String base64Key) {
        byte[] key = Base64Util.decodeFromBase64(base64Key);
        return encrypt(data, key);
    }

    /**
     * 解密
     *
     * @param data      待解密数据
     * @param base64Key 密钥
     * @return 明文
     */
    @SneakyThrows
    public static byte[] decrypt(byte[] data, String base64Key) {
        byte[] key = Base64Util.decodeFromBase64(base64Key);
        return decrypt(data, key);
    }
}
